package com.iwhalecloud.citybrain.flow.platform.manager.application.service;

import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.CandidateRelationShipEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.SpringUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.application.utils.StringUtils;
import com.iwhalecloud.citybrain.flow.platform.manager.common.ErrorCode;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.CustomFunctionVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.userentity.UserInfo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.FlowUserTaskCustomExpressionRepository;
import org.apache.commons.collections.CollectionUtils;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.*;

/**
　　* @description: 流程节点候选适配服务
　　* @author shenrm
　　* @date 2021/11/29 17:01
　　*/
@Component
public class FlowNodeCandidateServiceAdapter {

    @Autowired
    private UserService userService;

    @Autowired
    private UserRelationShipService userRelationShipService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private FlowUserTaskCustomExpressionRepository flowUserTaskCustomExpressionRepository;

    @Autowired
    private RuntimeService runtimeService;

    /**
     * 控制开关true是打开,false是关闭,默认是true:打开
     */
    @Value("${apply.user.enable:true}")
    private boolean controlSwith;

    /**
     * 获取流程节点候选人
     *
     * @param processInstanceId
     * @return
     */
    public String getFlowNodeCandidateUser(String processInstanceId) {
        FlowNodeCandidateService flowNodeCandidateService = null;
        if(controlSwith) {
            flowNodeCandidateService = SpringUtils.getBean("flowTaskNodeCandidateService",FlowNodeCandidateService.class);
        } else {
            flowNodeCandidateService = SpringUtils.getBean("flowApplyCandidateService", FlowNodeCandidateService.class);
        }
        if(Objects.isNull(flowNodeCandidateService)) {
            return null;
        }
        return flowNodeCandidateService.getFlowNodeCandidateUser(processInstanceId);
    }


    /**
     * 根据任务实例ID获取对应的任务处理人
     *
     * @param processInstanceId
     * @param taskId
     * @return
     */
    public String getAssignee(String processInstanceId, String taskId) {
        if(StringUtils.isBlank(taskId)) {
            return null;
        }

        // 根据流程实例ID获取历史处理的任务实例
        HistoricTaskInstance historyTask = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstanceId).taskId(taskId).singleResult();

        // 为空时,默认返回流程发起人
        if(Objects.isNull(historyTask)) {
            return null;
        }
        return historyTask.getAssignee();
    }



    /**
     * 处理后续节点候选人是【关系】和【自定义函数】类型
     *
     * @param dataType
     * @param code
     * @param processInstanceId
     * @param taskId
     * @param nodeCode
     * @return
     * @throws Exception
     */
    public Set<UserInfo> handleNextNodeCandidateUsers(String dataType, String code,
                                                      String processInstanceId, String taskId, String nodeCode) throws Exception {

        // 解析存储的人员信息
        Set<UserInfo> userInfoSet = new HashSet<>();
        if (Objects.equals(dataType,"RELATIONSHIP")){
            // 获取当前流程节点的处理人,默认取该整个流程实例的节点处理人,配置关闭,则取流程发起人
            String ngrUserId = null;

            // 如果设置的是拟稿人或拟稿人部门并且拟稿人为空,则直接抛出异常
            if (Objects.equals(code, CandidateRelationShipEnum.NGR.getCode()) ||
                    Objects.equals(code, CandidateRelationShipEnum.NGRBM.getCode())) {

                    // 获取拟稿人
                    ngrUserId = this.getFlowNodeCandidateUser(processInstanceId);

                    // 拟稿人为空时,处理不了,直接抛出异常
                    if(StringUtils.isBlank(ngrUserId)) {
                        throw new Exception(ErrorCode.NGR_USER_NOT_EXIST.errMessage());
                    }
            }

            // 如果是拟稿人,则直接添加ngrUserId
            if (Objects.equals(code, CandidateRelationShipEnum.NGR.getCode())) {
                UserInfo userInfo = new UserInfo();
                userInfo.setUserCode(ngrUserId);
                UserInfo userInfoObj = userService.getUserInfoObj(ngrUserId);
                userInfo.setUserName(userInfoObj == null ? "" : userInfoObj.getUserName());
                userInfoSet.add(userInfo);
            } else if (Objects.equals(code, CandidateRelationShipEnum.NGRBM.getCode())) { // 如果是拟稿人部门,则根据拟稿人获取对应的部门列表,再根据所属的部门列表获取对应的人员列表
                Set<UserInfo> ngrBmUserInfoSet = userRelationShipService.getUserInfoSetByUserId(ngrUserId);
                userInfoSet.addAll(ngrBmUserInfoSet);
            } else if (Objects.equals(code, CandidateRelationShipEnum.DQRBM.getCode())) {
                if(StringUtils.isBlank(taskId)) {
                    throw new Exception(String.format(ErrorCode.TASK_NODE_NOT_EXIST.errMessage(),nodeCode));
                }
                // 根据该流程实例ID和节点的任务实例ID获取该节点的历史任务处理人
                String assignee = this.getAssignee(processInstanceId, taskId);
                if(StringUtils.isBlank(assignee)) {
                    throw new Exception(String.format(ErrorCode.DQR_USER_NOT_EXIST.errMessage(),nodeCode));
                }

                // 再根据该节点处理人获取对应的部门以及部门对应下的人员信息列表
                Set<UserInfo> dqrBmUserInfoSet = userRelationShipService.getUserInfoSetByUserId(assignee);
                userInfoSet.addAll(dqrBmUserInfoSet);
            }
        } else if(Objects.equals(dataType, "FUNCTION")) {
//            if(StringUtils.isBlank(taskId)) {
//                throw new Exception(String.format(ErrorCode.TASK_NODE_NOT_EXIST.errMessage(),nodeCode));
//            }
            // 拟稿人ID
            String ngrUserId = this.getFlowNodeCandidateUser(processInstanceId);

            // 根据该流程实例ID和节点的任务实例ID获取该节点的历史任务处理人
            String assignee = null;
            if(StringUtils.isBlank(assignee)) {
                throw new Exception(String.format(ErrorCode.DQR_USER_NOT_EXIST.errMessage(),nodeCode));
            }
            // 获取流程变量
            Map<String,Object> variables = runtimeService.getVariables(processInstanceId);

            // 调接口返回人员列表
//            List<CustomFunctionVo> functionResult = flowUserTaskCustomExpressionRepository.getCustomFunctionByFunId(code, ngrUserId, assignee);
            List<CustomFunctionVo> functionResult =  flowUserTaskCustomExpressionRepository.getCustomFunctionByFunId(code, ngrUserId, assignee,variables);

            if(CollectionUtils.isNotEmpty(functionResult)) {
                for (CustomFunctionVo customFunctionVo : functionResult) {
                    UserInfo userInfo = new UserInfo();
                    userInfo.setUserCode(customFunctionVo.getUserId());
                    userInfo.setUserName(customFunctionVo.getName());
                    userInfoSet.add(userInfo);
                }
            }
        }
        return userInfoSet;
    }
}
